		TITLE	REXEPACK - Copyright (c) SLR Systems 1994

		INCLUDE MACROS
		INCLUDE	SEGMENTS

		PUBLIC	REAL_EXEPACK,REXE_INIT,REAL_EXEPACK_FLUSH
		PUBLIC	MOVE_PACK_DATA

if	fg_segm
		PUBLIC	GET_NEXT_BUFFER,INIT_INOUTBUF
endif


		.DATA

		EXTERNDEF	TEMP_RECORD:BYTE,EXEPACK_TEMP:BYTE

		EXTERNDEF	EXETABLE:DWORD,R_DONT_PACK:DWORD,EXEPACK_DANGLE_LEN:DWORD,EXEPACK_AX_SAVE:DWORD
		EXTERNDEF	EXEPACK_TAIL_LIMIT:DWORD,EXEPACK_LIMIT:DWORD,EXEPACK_DI_SAVE:DWORD,OLD_HIGH_WATER:DWORD
		EXTERNDEF	HIGH_WATER:DWORD,NEW_REPT_ADDR:DWORD,PACK_SO_FAR:DWORD,TARG_ADDR:DWORD,EXEPACK_SRC:DWORD
		EXTERNDEF	EXEPACK_BYTES:DWORD,EXEPACK_ZEROS:DWORD,FIX2_SM_START:DWORD,FIX2_SKIP_BYTES:DWORD

		EXTERNDEF	EXEPACK_STRUCTURE:SEQ_STRUCT

		EXTERNDEF	EXEPACK_ROUTINE:DWORD


;PACK		SEGMENT PARA PUBLIC 'UNPACK_DATA'

		EXTERNDEF	INITIAL_COUNT:WORD

;PACK		ENDS


		.CODE	PASS2_TEXT

		EXTERNDEF	CONVERT_SUBBX_TO_EAX:PROC,RELEASE_BLOCK:PROC,REAL_RELOC_FLUSH:PROC,MOVE_EAX_TO_EDX_FINAL:PROC
		EXTERNDEF	STORE_EAXECX_EDXEBX_RANDOM:PROC,RELEASE_EXETABLE_5:PROC


COMMENT ~

	MUST HAVE AT LEAST THIS MANY DUPLICATES TO TRY IT...

FOR	REAL

		ANY	INITIAL MID
BYTES            6        6      2
WORDS            4        3      2
DWORDS           2        2      2


~

REAL_EXEPACK	PROC
		;
		;CONTINUE WHERE YOU LEFT OFF, COMPRESSING THIS DATA...
		;
		;RESTORE THE DANGLING 8 BYTES
		;
		MOV	EAX,EXEPACK_ROUTINE

		PUSH	EAX
		JMP	INIT_INOUTBUF

REAL_EXEPACK	ENDP


REXE_INIT	PROC
		;
		;ESI POINTS TO FIRST VALID POSITION
		;
		XOR	EDX,EDX
		MOV	EAX,R_DONT_PACK

		CMP	EAX,EDX
		JZ	MAIN_LOOP_CHECK

		JMP	L9$

L1$:
		MOV	EAX,EBX
		MOV	ECX,R_DONT_PACK

		SUB	EAX,ESI

		CMP	ECX,EAX
		JA	L2$

		MOV	EAX,ECX
L2$:
		ADD	EDX,EAX
		ADD	ESI,EAX

		SUB	ECX,EAX

		MOV	R_DONT_PACK,ECX
		JZ	MAIN_LOOP_CHECK

		CALL	FLUSH_GET_NEXT_BUFFER	;COPY, THEN GET NEW
L9$:
		CMP	EXEPACK_LIMIT,EBX
		JNZ	L1$

		JMP	EXEPACK_FINISH

REXE_INIT	ENDP


MAIN_LOOP:
		MOV	AL,[ESI]
		MOV	CL,[ESI+4]

		CMP	AL,CL
		JNZ	MAIN_NEXT

		MOV	AH,[ESI+1]
		MOV	CH,[ESI+5]

		CMP	AH,CH
		JZ	MAYBE
MAIN_NEXT:
MAYBE_RET:
		INC	ESI
		INC	EDX		;COUNT BYTES THIS GROUP
MLC_1:
		CMP	EBX,ESI
		JA	MAIN_LOOP
MAIN_FILL:
		CALL	FLUSH_GET_NEXT_BUFFER	;COPY, THEN GET NEW
MAIN_LOOP_CHECK:
		CMP	EXEPACK_LIMIT,EBX
		JNZ	MLC_1

		JMP	EXEPACK_FINISH

MAYBE:
		MOV	CL,[ESI+2]

		MOV	CH,[ESI+3]

		CMP	CX,AX
		JZ	B_OR_W
		;
		;WELL, ONLY CHANCE IS 2 DWORDS
		;
MAYBE_DWORDS:
		MOV	AL,[ESI+6]

		MOV	AH,[ESI+7]

		CMP	CX,AX
		JNZ	MAYBE_RET

		JMP	YES_DWORDS

B_OR_W:
		;
		;GOT 3 WORDS MATCHING
		;
		CMP	AL,AH		;BYTES?
		JZ	YES_BYTES
		;
		;NEED TWO MORE MATCH FOR WORDS
		;
		CMP	6[ESI],AX
		JZ	YES_WORDS
WORDS_3_ENUF?:
		TEST	EDX,EDX
		JNZ	MAYBE_RET

		CMP	PACK_SO_FAR,EDX
		JNZ	MAYBE_RET
YES_WORDS:
		CALL	STORE_BYTES_DX_1	;DX BYTES, 1 ITERATION

		MOV	AX,[ESI]
		MOV	EDI,ESI
YES_WORD:
		;
		;WE AT LEAST HAVE 3 WORDS, SEE WHAT ELSE WE CAN COME UP WITH.
		;
		MOV	ECX,EBX
		XOR	EDX,EDX

		SUB	ECX,EDI			;MAX WE CAN SCAN IN ONE SHOT

		SHR	ECX,1
		JZ	ANOTHER_WORD

		MOV	EDX,ECX			;# WE SCANNED...

		REPE	SCASW

		JZ	ANOTHER_WORD

		SUB	EDX,ECX			;# FOUND
		LEA	ESI,[EDI-2]

		DEC	EDX
		CALL	STORE_WORDTYPE		;SPECIAL CASES HANDLED...

		XOR	EDX,EDX
		JMP	MAIN_LOOP_CHECK

ANOTHER_WORD:
		;
		;STILL CRUISING, GET ANOTHER BUFFER PLEASE
		;
		ADD	PACK_SO_FAR,EDX
		MOV	ESI,EDI

		CALL	GET_NEXT_BUFFER

		MOV	EDI,ESI
		JNC	YES_WORD

		XOR	EDX,EDX
		CALL	STORE_WORDTYPE

		XOR	EDX,EDX
		JMP	EXEPACK_FINISH

YES_BYTES:
		;
		;GOT 6
		;
YES_BYTE:
		CALL	STORE_BYTES_DX_1	;STORE PREVIOUS COUNT

		MOV	AL,[ESI]
		MOV	EDI,ESI
		;
		;WE AT LEAST HAVE 6 BYTES, SEE WHAT ELSE WE CAN COME UP WITH.
		;WE ARE SCANNING FOR BYTES...
		;
YB_1:
		MOV	ECX,EBX

		SUB	ECX,EDI			;MAX WE CAN SCAN IN ONE SHOT
		JZ	ANOTHER_BYTE

		MOV	EDX,ECX			;# WE SCANNED...

		REPE	SCASB

		JZ	ANOTHER_BYTE

		SUB	EDX,ECX			;# FOUND
		LEA	ESI,[EDI-1]

		DEC	EDX
		CALL	STORE_BYTETYPE		;SPECIAL CASES HANDLED...

		XOR	EDX,EDX
		JMP	MAIN_LOOP_CHECK

YES_DWORDS:
		CALL	STORE_BYTES_DX_1

		MOV	EAX,[ESI]
		MOV	EDI,ESI

		;WE ARE SCANNING FOR DWORDS...
YD_1:
		MOV	ECX,EBX
		XOR	EDX,EDX

		SUB	ECX,ESI			;MAX WE CAN SCAN IN ONE SHOT

		SHR	ECX,2
		JZ	ANOTHER_DWORD

		MOV	EDX,ECX			;# WE SCANNED...

		REPE	SCASD

		JZ	ANOTHER_DWORD

		SUB	EDX,ECX			;# FOUND
		LEA	ESI,[EDI-4]

		DEC	EDX
		CALL	STORE_DWORDTYPE 	;SPECIAL CASES HANDLED...

		XOR	EDX,EDX
		JMP	MAIN_LOOP_CHECK

ANOTHER_BYTE:
		;
		;STILL CRUISING, GET ANOTHER BUFFER PLEASE
		;
		;BX DUPLICATE BYTES LIKE AL HAVE BEEN STORED
		;
		ADD	PACK_SO_FAR,EDX
		MOV	ESI,EDI

		CALL	GET_NEXT_BUFFER

		MOV	EDI,ESI
		JNC	YB_1

		XOR	EDX,EDX
		CALL	STORE_BYTETYPE

		XOR	EDX,EDX
		JMP	EXEPACK_FINISH

ANOTHER_DWORD:
		ADD	PACK_SO_FAR,EDX
		MOV	ESI,EDI

		CALL	GET_NEXT_BUFFER

		MOV	EDI,ESI
		JNC	YD_1

		XOR	EDX,EDX
		CALL	STORE_DWORDTYPE

		XOR	EDX,EDX
		JMP	EXEPACK_FINISH


EXEPACK_FINISH	PROC
		;
		;FLUSH PARTIAL BLOCK
		;
;		CALL	STORE_BYTES_DX_1
		;
		;FLUSH DANGLING PIECE
		;
		MOV	EDX,EXEPACK_LIMIT

		SUB	EDX,ESI

		ADD	ESI,EDX
		JMP	STORE_BYTES_DX_1
;		RET

EXEPACK_FINISH	ENDP


MOVE_DX_TARG	PROC	NEAR
		;
		;MOVE DX BYTES FROM DS:SI-DX TO TARG_ADDR, UPDATE TARG_ADDR
		;AND PACK_SO_FAR
		;
		ADD	PACK_SO_FAR,EDX
		JZ	L9$
MOVE_DX_TARG_A::
		MOV	EAX,ESI
		MOV	ECX,EDX

		SUB	EAX,EDX
		MOV	EDX,TARG_ADDR

		TEST	ECX,ECX
		JZ	L8$

		ADD	TARG_ADDR,ECX
		CALL	MOVE_PACK_DATA
L8$:
		XOR	EDX,EDX
L9$:
		RET

MOVE_DX_TARG	ENDP


FGNB_FULL	LABEL	PROC
		;
		;USE STORE_BYTES_DX_1 TO GET RID OF 32K OF STUFF
		;
		SUB	EAX,32K		;# OF BYTES > 32K

		SUB	ESI,EAX
		SUB	EDX,EAX

		PUSH	EAX
		CALL	STORE_BYTES_DX_1

		POP	EDX

		ADD	ESI,EDX

FLUSH_GET_NEXT_BUFFER	LABEL	PROC
		;
		;MAKE SURE NOT >32K-1...
		;
		MOV	EAX,PACK_SO_FAR

		ADD	EAX,EDX

		CMP	EAX,32K
		JAE	FGNB_FULL

		CALL	MOVE_DX_TARG
		;
GET_NEXT_BUFFER PROC
		;
		;
		POP	ECX
		MOV	EXEPACK_AX_SAVE,EAX

		MOV	EXEPACK_ROUTINE,ECX
		MOV	EXEPACK_DI_SAVE,EDI
		;
		;
		;
		LEA	ESI,[ESI-4]		;FOR DWORD CHECKING...
		MOV	ECX,EXEPACK_LIMIT

		SUB	ECX,ESI
		MOV	EDI,OFF TEMP_RECORD		;MOVE TAIL TO BOTTOM

		REP	MOVSB
		;
		;NOW, MOVE ZEROS IF ANY
		;
		MOV	ECX,EXEPACK_ZEROS

		TEST	ECX,ECX
		JZ	L5$
		;
		;MOVE SMALLER OF EXEPACK_ZEROS AND 4K
		;
		CMP	ECX,4K
		JBE	L2$

		MOV	ECX,4K
L2$:
		SUB	EXEPACK_ZEROS,ECX
		XOR	EAX,EAX

		OPTI_STOSB
L3$:
		MOV	EBX,EDI
		MOV	EAX,EXEPACK_TAIL_LIMIT

		SUB	EBX,EAX
		MOV	ESI,OFF TEMP_RECORD+4

		CMP	EBX,ESI
		JB	L5$

		MOV	EAX,EXEPACK_AX_SAVE
		MOV	EXEPACK_LIMIT,EDI

		MOV	EDI,EXEPACK_DI_SAVE
		XOR	EDX,EDX

		JMP	EXEPACK_ROUTINE

L5$:
		;
		;NEED TO MOVE SOME DATA FROM PACKTABLE
		;
		MOV	ESI,EXEPACK_SRC

		MOV	EBX,ESI
		AND	ESI,PAGE_SIZE-1

		SHR	EBX,PAGE_BITS
		MOV	EAX,PAGE_SIZE
		;
		;MOVE SMALLER OF 4K, EXEPACK_BYTES, AND PAGE_SIZE-SI
		;
		SUB	EAX,ESI
		MOV	ECX,4K

		CMP	EAX,ECX
		JA	L51$

		MOV	ECX,EAX
L51$:
		MOV	EAX,EXEPACK_BYTES

		CMP	EAX,ECX
		JA	L55$

		MOV	ECX,EAX
L55$:
		;
		;ECX IS # OF BYTES TO MOVE
		;
		TEST	ECX,ECX
		JZ	L7$

		LEA	EBX,EXETABLE[EBX*4]
		CALL	CONVERT_SUBBX_TO_EAX

		ADD	ESI,EAX
		MOV	EDX,ECX

		OPTI_MOVSB

		ADD	EXEPACK_SRC,EDX
		SUB	ESI,EAX
		;
		;IF SI=PAGE_SIZE, OR EXEPACK_BYTES = 0, RELEASE BLOCK
		;
		SUB	EXEPACK_BYTES,EDX
		JZ	L6$

		CMP	ESI,PAGE_SIZE
		JNZ	L3$
L6$:
		XOR	ECX,ECX
		MOV	EAX,[EBX]

		MOV	[EBX],ECX
		CALL	RELEASE_BLOCK

		JMP	L3$

L7$:
		MOV	EAX,FIX2_SKIP_BYTES

		TEST	EAX,EAX
		JZ	L71$

		CALL	RELEASE_EXETABLE_5
L71$:
		BITT	EXEPACK_FLUSHING
		JNZ	L8$
		;
		;NO BYTES LEFT, MOVE PARTIAL BACK TO EXEPACK_TEMP
		;
		MOV	ECX,EDI
		MOV	ESI,OFF TEMP_RECORD

		MOV	EDI,OFF EXEPACK_TEMP
		SUB	ECX,ESI

		MOV	EXEPACK_DANGLE_LEN,ECX

		REP	MOVSB
		;
		;SET UP FOR MASTER-RETURN
		;
		RET

L8$:
		MOV	ESI,OFF TEMP_RECORD+4
		MOV	EBX,EDI

		MOV	EAX,EXEPACK_AX_SAVE
		MOV	EXEPACK_LIMIT,EDI

		MOV	EDI,EXEPACK_DI_SAVE
		XOR	EDX,EDX

		CMP	ESP,-1

		JMP	EXEPACK_ROUTINE

GET_NEXT_BUFFER ENDP


REAL_EXEPACK_FLUSH	PROC

		PUSHM	EDI,ESI,EBX
		MOV	ESI,OFF EXEPACK_TEMP

		MOV	EDI,OFF TEMP_RECORD		;MOVE TAIL TO BOTTOM
		MOV	ECX,EXEPACK_DANGLE_LEN

		REP	MOVSB

		MOV	ESI,OFF TEMP_RECORD+4
		MOV	EBX,EDI

		MOV	EAX,EXEPACK_AX_SAVE
		MOV	EXEPACK_LIMIT,EDI

		MOV	EDI,EXEPACK_DI_SAVE
		XOR	EDX,EDX

		MOV	EXEPACK_DANGLE_LEN,4
		SETT	EXEPACK_FLUSHING	;CLEARS CARRY TOO

		CALL	EXEPACK_ROUTINE

		POPM	EBX,ESI,EDI

		RET

REAL_EXEPACK_FLUSH	ENDP


INIT_INOUTBUF	PROC
		;
		;INITIALIZE STUFF
		;
		;POINT TO DANGLE
		;
		MOV	ESI,OFF EXEPACK_TEMP
		MOV	EAX,EXEPACK_DANGLE_LEN

		ADD	EAX,ESI
		MOV	ECX,FIX2_SM_START

		MOV	EXEPACK_LIMIT,EAX
		MOV	EDX,OLD_HIGH_WATER
		;
		;HANDLE INTERMEDIATE ZEROS
		;
		SUB	ECX,EDX
		MOV	EDX,HIGH_WATER

		MOV	EXEPACK_ZEROS,ECX
		MOV	EAX,FIX2_SM_START

		MOV	OLD_HIGH_WATER,EDX
		SUB	EDX,EAX

		MOV	EAX,FIX2_SKIP_BYTES
		MOV	EXEPACK_BYTES,EDX

		MOV	EXEPACK_SRC,EAX
		MOV	EAX,EXEPACK_AX_SAVE

		MOV	ESI,OFF EXEPACK_TEMP+4
		JMP	GET_NEXT_BUFFER

INIT_INOUTBUF	ENDP


STORE_DWORDTYPE PROC	NEAR
		;
		;EDX MORE DWORDS FOUND, FLUSH THIS ALL
		;
		MOV	EAX,PACK_SO_FAR

		ADD	EAX,EDX
		JZ	L9$		;NONE REALLY, SKIP IT

		CMP	EAX,1000H
		JA	L1$
L0$:
		ADD	EAX,0E000H-1

		MOV	PACK_SO_FAR,EAX
FLUSH_DWORDTYPE:
		MOV	EDX,4
		CALL	MOVE_DX_TARG_A	;MV DX BYTES FM DS:SI-DX TO TARG_ADDR

		JMP	STORE_PACK	;STORE PACK_SO_FAR AT REPT LOCATION

L1$:

L2$:
		MOV	PACK_SO_FAR,0EFFFH

		PUSH	EAX
		CALL	FLUSH_DWORDTYPE

		POP	EAX

		SUB	EAX,1000H
		JZ	L9$

		CMP	EAX,1000H
		JA	L2$

		JMP	L0$

L9$:
		RET

STORE_DWORDTYPE ENDP


STORE_WORDTYPE	PROC	NEAR
		;
		;EDX MORE WORDS FOUND, FLUSH THIS ALL
		;
		MOV	EAX,PACK_SO_FAR

		ADD	EAX,EDX
		JZ	L9$
L0$:
		CMP	EAX,4000H
		JA	L1$

		ADD	EAX,0A000H-1

		MOV	PACK_SO_FAR,EAX
FLUSH_WORDTYPE:
		MOV	EDX,2
		CALL	MOVE_DX_TARG_A	;MV DX BYTES FM DS:SI-DX TO TARG_ADDR

		JMP	STORE_PACK	;STORE PACK_SO_FAR AT REPT LOCATION

L1$:
		MOV	PACK_SO_FAR,0DFFFH

		PUSH	EAX
		CALL	FLUSH_WORDTYPE

		POP	EAX

		SUB	EAX,4000H
		JMP	L0$

L9$:
		RET

STORE_WORDTYPE	ENDP


STORE_BYTETYPE	PROC	NEAR
		;
		;DX MORE BYTES FOUND, FLUSH THIS ALL
		;
		MOV	EAX,PACK_SO_FAR

		ADD	EAX,EDX
		JZ	L9$
L0$:
		CMP	EAX,2000H
		JA	CHANGE_TO_WORD

		ADD	EAX,8000H-1

		MOV	PACK_SO_FAR,EAX
FLUSH_BYTETYPE:
		MOV	EDX,1
		CALL	MOVE_DX_TARG_A	;MV DX BYTES FM DS:SI-DX TO TARG_ADDR

STORE_PACK::
		PUSH	ESI
		MOV	ESI,OFF PACK_SO_FAR

		JMP	SBDX_1

L9$:
		RET

CHANGE_TO_WORD:
		TEST	AL,1
		JNZ	L1$

		SHR	EAX,1
		XOR	EDX,EDX

		MOV	PACK_SO_FAR,EAX
		MOV	AL,[ESI-1]

		MOV	[ESI-2],AL
		JMP	STORE_WORDTYPE

L1$:
		;
		;ODD # OF BYTES, GENERATE 1FFFH BYTES FIRST, THEN TRY AGAIN
		;
		MOV	PACK_SO_FAR,9FFEH

		PUSH	EAX
		CALL	FLUSH_BYTETYPE

		POP	EAX

		SUB	EAX,1FFFH
		JMP	L0$

STORE_BYTETYPE	ENDP


STORE_BYTES_DX_1	PROC	NEAR
		;
		;
		;
		CMP	EDX,7
		JA	L5$

		MOV	EAX,PACK_SO_FAR

		OR	EAX,EAX
		JNZ	L5$

		CMP	EDX,2
		JB	L5$
		;
		;MAYBE WE CAN SQUEEZE JUST A LITTLE BIT MORE...
		;
		;FIRST, TRY FOR DX MATCHING BYTES...
		;
		SUB	ESI,EDX
		MOV	ECX,EDX

		MOV	EDI,ESI
		MOV	AL,[ESI]

		REPE	SCASB

		JZ	L1$		;YES!

		MOV	EDI,ESI
		MOV	ECX,EDX

		SHR	ECX,1
		JC	L4$		;CANNOT!

		MOV	AX,[ESI]

		REPE	SCASW

		LEA	ESI,[ESI+EDX]
		JNZ	L5$		;NOPE!
		;
		;WORDS
		;
		SHR	EDX,1
		JMP	STORE_WORDTYPE

L1$:
		;
		;BYTES
		;
		ADD	ESI,EDX
		JMP	STORE_BYTETYPE

L4$:
		ADD	ESI,EDX
L5$:
		;
		;HANDLE CROSSING 32K BOUNDARY...
		;
		MOV	EAX,PACK_SO_FAR

		ADD	EAX,EDX

		CMP	EAX,32K
		JBE	L6$

		SUB	EAX,32K

		PUSH	EAX		;AMOUNT TO MOVE NEXT TIME
		SUB	ESI,EAX

		SUB	EDX,EAX
		CALL	L6$

		POP	EDX

		ADD	ESI,EDX
L6$:
		CALL	MOVE_DX_TARG

		MOV	EAX,PACK_SO_FAR

		OR	EAX,EAX
		JZ	L9$

		PUSH	ESI
		MOV	ESI,OFF PACK_SO_FAR

		DEC	PACK_SO_FAR
SBDX_1::
		;
		;HAS FIRST REPT_WORD BEEN STORED IN UNPACKER YET?
		;
		GETT	AL,FIRST_REPT_STORED

		OR	AL,AL
		JZ	L8$

		MOV	EDX,NEW_REPT_ADDR
		MOV	ECX,2

		MOV	EAX,ESI
		CALL	MOVE_PACK_DATA
L81$:
		POP	ESI
		MOV	ECX,TARG_ADDR

		XOR	EAX,EAX
		MOV	NEW_REPT_ADDR,ECX

		ADD	ECX,2
		MOV	PACK_SO_FAR,EAX

		MOV	TARG_ADDR,ECX
L9$:
		RET

L8$:
		SETT	FIRST_REPT_STORED

		MOV	EAX,[ESI]
		ADD	ESI,2

		MOV	INITIAL_COUNT,AX
		JMP	L81$

STORE_BYTES_DX_1	ENDP


MOVE_PACK_DATA	PROC

if	fg_slrpack
		BITT	SLRPACK_FLAG
		JZ	UN

		PUSH	EBX
		MOV	EBX,EDX

		MOV	EDX,OFF EXEPACK_STRUCTURE
		CALL	STORE_EAXECX_EDXEBX_RANDOM

		POP	EBX

		RET
UN:
endif
		JMP	MOVE_EAX_TO_EDX_FINAL

MOVE_PACK_DATA	ENDP


		END

